//------------------------------------------------------------------------------
// Title      : Demo testbench
// Project    : Tri-Mode Ethernet MAC
//------------------------------------------------------------------------------
// File       : demo_tb.v
// ------------------------------------------------------------------------------
// (c) Copyright 2004-2008 Xilinx, Inc. All rights reserved.
//
// This file contains confidential and proprietary information
// of Xilinx, Inc. and is protected under U.S. and
// international copyright and other intellectual property
// laws.
//
// DISCLAIMER
// This disclaimer is not a license and does not grant any
// rights to the materials distributed herewith. Except as
// otherwise provided in a valid license issued to you by
// Xilinx, and to the maximum extent permitted by applicable
// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
// (2) Xilinx shall not be liable (whether in contract or tort,
// including negligence, or under any other theory of
// liability) for any loss or damage of any kind or nature
// related to, arising under or in connection with these
// materials, including for any direct, or any indirect,
// special, incidental, or consequential loss or damage
// (including loss of data, profits, goodwill, or any type of
// loss or damage suffered as a result of any action brought
// by a third party) even if such damage or loss was
// reasonably foreseeable or Xilinx had been advised of the
// possibility of the same.
//
// CRITICAL APPLICATIONS
// Xilinx products are not designed or intended to be fail-
// safe, or for use in any application requiring fail-safe
// performance, such as life-support or safety devices or
// systems, Class III medical devices, nuclear facilities,
// applications related to the deployment of airbags, or any
// other applications that could lead to death, personal
// injury, or severe property or environmental damage
// (individually and collectively, "Critical
// Applications"). Customer assumes the sole risk and
// liability of any use of Xilinx products in Critical
// Applications, subject only to applicable laws and
// regulations governing limitations on product liability.
//
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
// PART OF THIS FILE AT ALL TIMES. 
// ------------------------------------------------------------------------------
// Description: This testbench will exercise the ports of the MAC core
//              to demonstrate the functionality.
//------------------------------------------------------------------------------
//
// This testbench performs the following operations on the MAC core
// and its design example:

//  - The clock divide register is set for MDIO operation.
//  - Flow control is disabled on both transmit and receive.

//  - Four frames are then pushed into the receiver from the PHY
//    interface (GMII/MII or RGMII):
//    The first is of minimum length (Length/Type = Length = 46 bytes).
//    The second frame sets Length/Type to Type = 0x8000.
//    The third frame has an error inserted.
//    The fourth frame only sends 4 bytes of data: the remainder of the
//    data field is padded up to the minimum frame length i.e. 46 bytes.

//  - These frames are then parsed from the MAC into the MAC's design
//    example.  The design example provides a MAC client loopback
//    function so that frames which are received without error will be
//    looped back to the MAC transmitter and transmitted back to the
//    testbench.  The testbench verifies that this data matches that
//    previously injected into the receiver.

//  - The four frames are then re-sent at both 100Mb/s and 10Mb/s.

//----------------------------------------------------------------------
//                         DEMONSTRATION TESTBENCH                     |
//                                                                     |
//                                                                     |
//     ----------------------------------------------                  |
//     |           TOP LEVEL WRAPPER (DUT)          |                  |
//     |  -------------------    ----------------   |                  |
//     |  | CLIENT LOOPBACK |    | TRI-MODE     |   |                  |
//     |  | DESIGN EXAMPLE  |    | ETHERNET MAC |   |                  |
//     |  |                 |    | CORE         |   |                  |
//     |  |                 |    |              |   |       Monitor    |
//     |  |         ------->|--->|          Tx  |-------->  Frames     |
//     |  |         |       |    |          PHY |   |                  |
//     |  |         |       |    |          I/F |   |                  |
//     |  |         |       |    |              |   |                  |
//     |  |         |       |    |              |   |                  |
//     |  |         |       |    |              |   |                  |
//     |  |         |       |    |          Rx  |   |                  |
//     |  |         |       |    |          PHY |   |                  |
//     |  |         --------|<---|          I/F |<-------- Generate    |
//     |  |                 |    |              |   |      Frames      |
//     |  -------------------    ----------------   |                  |
//     --------------------------------^-------------                  |
//                                     |                               |
//                                     |                               |
//                                 Stimulate                           |
//                               Management I/F                        |
//                               (if present)                          |
//                                                                     |
//----------------------------------------------------------------------


`timescale 1ps / 1ps


//------------------------------------------------------------------------------
// This module abstracts the frame data for simpler manipulation
//------------------------------------------------------------------------------

module frame_typ;

   // data field
   reg [7:0]  data  [0:61];
   reg        valid [0:61];
   reg        error [0:61];

   // Indicate to the testbench that the frame contains an error
   reg        bad_frame;

`define FRAME_TYP [8*62+62+62+8*4+4+4+8*4+4+4+1:1]

   reg `FRAME_TYP bits;

   function `FRAME_TYP tobits;
      input dummy;
      begin
    bits = {data[ 0],  data[ 1],  data[ 2],  data[ 3],  data[ 4],
            data[ 5],  data[ 6],  data[ 7],  data[ 8],  data[ 9],
            data[10],  data[11],  data[12],  data[13],  data[14],
            data[15],  data[16],  data[17],  data[18],  data[19],
            data[20],  data[21],  data[22],  data[23],  data[24],
            data[25],  data[26],  data[27],  data[28],  data[29],
            data[30],  data[31],  data[32],  data[33],  data[34],
            data[35],  data[36],  data[37],  data[38],  data[39],
            data[40],  data[41],  data[42],  data[43],  data[44],
            data[45],  data[46],  data[47],  data[48],  data[49],
            data[50],  data[51],  data[52],  data[53],  data[54],
            data[55],  data[56],  data[57],  data[58],  data[59],
            data[60],  data[61],

            valid[ 0], valid[ 1], valid[ 2], valid[ 3], valid[ 4],
            valid[ 5], valid[ 6], valid[ 7], valid[ 8], valid[ 9],
            valid[10], valid[11], valid[12], valid[13], valid[14],
            valid[15], valid[16], valid[17], valid[18], valid[19],
            valid[20], valid[21], valid[22], valid[23], valid[24],
            valid[25], valid[26], valid[27], valid[28], valid[29],
            valid[30], valid[31], valid[32], valid[33], valid[34],
            valid[35], valid[36], valid[37], valid[38], valid[39],
            valid[40], valid[41], valid[42], valid[43], valid[44],
            valid[45], valid[46], valid[47], valid[48], valid[49],
            valid[50], valid[51], valid[52], valid[53], valid[54],
            valid[55], valid[56], valid[57], valid[58], valid[59],
            valid[60], valid[61],

            error[ 0], error[ 1], error[ 2], error[ 3], error[ 4],
            error[ 5], error[ 6], error[ 7], error[ 8], error[ 9],
            error[10], error[11], error[12], error[13], error[14],
            error[15], error[16], error[17], error[18], error[19],
            error[20], error[21], error[22], error[23], error[24],
            error[25], error[26], error[27], error[28], error[29],
            error[30], error[31], error[32], error[33], error[34],
            error[35], error[36], error[37], error[38], error[39],
            error[40], error[41], error[42], error[43], error[44],
            error[45], error[46], error[47], error[48], error[49],
            error[50], error[51], error[52], error[53], error[54],
            error[55], error[56], error[57], error[58], error[59],
            error[60], error[61],

            bad_frame};
    tobits = bits;
      end
   endfunction // tobits

   task frombits;
      input `FRAME_TYP frame;
      begin
    bits = frame;
           {data[ 0],  data[ 1],  data[ 2],  data[ 3],  data[ 4],
            data[ 5],  data[ 6],  data[ 7],  data[ 8],  data[ 9],
            data[10],  data[11],  data[12],  data[13],  data[14],
            data[15],  data[16],  data[17],  data[18],  data[19],
            data[20],  data[21],  data[22],  data[23],  data[24],
            data[25],  data[26],  data[27],  data[28],  data[29],
            data[30],  data[31],  data[32],  data[33],  data[34],
            data[35],  data[36],  data[37],  data[38],  data[39],
            data[40],  data[41],  data[42],  data[43],  data[44],
            data[45],  data[46],  data[47],  data[48],  data[49],
            data[50],  data[51],  data[52],  data[53],  data[54],
            data[55],  data[56],  data[57],  data[58],  data[59],
            data[60],  data[61],

            valid[ 0], valid[ 1], valid[ 2], valid[ 3], valid[ 4],
            valid[ 5], valid[ 6], valid[ 7], valid[ 8], valid[ 9],
            valid[10], valid[11], valid[12], valid[13], valid[14],
            valid[15], valid[16], valid[17], valid[18], valid[19],
            valid[20], valid[21], valid[22], valid[23], valid[24],
            valid[25], valid[26], valid[27], valid[28], valid[29],
            valid[30], valid[31], valid[32], valid[33], valid[34],
            valid[35], valid[36], valid[37], valid[38], valid[39],
            valid[40], valid[41], valid[42], valid[43], valid[44],
            valid[45], valid[46], valid[47], valid[48], valid[49],
            valid[50], valid[51], valid[52], valid[53], valid[54],
            valid[55], valid[56], valid[57], valid[58], valid[59],
            valid[60], valid[61],

            error[ 0], error[ 1], error[ 2], error[ 3], error[ 4],
            error[ 5], error[ 6], error[ 7], error[ 8], error[ 9],
            error[10], error[11], error[12], error[13], error[14],
            error[15], error[16], error[17], error[18], error[19],
            error[20], error[21], error[22], error[23], error[24],
            error[25], error[26], error[27], error[28], error[29],
            error[30], error[31], error[32], error[33], error[34],
            error[35], error[36], error[37], error[38], error[39],
            error[40], error[41], error[42], error[43], error[44],
            error[45], error[46], error[47], error[48], error[49],
            error[50], error[51], error[52], error[53], error[54],
            error[55], error[56], error[57], error[58], error[59],
            error[60], error[61],

            bad_frame} = bits;
      end
   endtask // frombits

endmodule // frame_typ



//------------------------------------------------------------------------------
// This module is the demonstration testbench
//------------------------------------------------------------------------------

module testbench;

  //----------------------------------------------------------------------------
  // Constants for Configuration Register Addresses
  //----------------------------------------------------------------------------

  // Management configuration register address   (0x340)
  reg [8:0] CONFIG_MANAGEMENT_ADD;

  // Flow control configuration register address (0x2C0)
  reg [8:0] CONFIG_FLOW_CTRL_ADD;

  // Receiver configuration register address   (0x240)
  reg [8:0] RECEIVER_ADD;

  // Transmitter configuration register address  (0x280)
  reg [8:0] TRANSMITTER_ADD;

  // EMAC configuration register address (0x300)
  reg [8:0] EMAC_CONFIG_ADD;

  // Unicast Word 0 configuration register address (0x380)
  reg [8:0] CONFIG_UNI0_CTRL_ADD;

  // Unicast Word 1 configuration register address (0x384)
  reg [8:0] CONFIG_UNI1_CTRL_ADD;

  // Address Filter configuration register address (0x390)
  reg [8:0] CONFIG_ADDR_CTRL_ADD;

  // Set up constants values....
  initial
  begin

    // Management configuration register address     (0x340)
    CONFIG_MANAGEMENT_ADD = 9'b101000000;

    // Flow control configuration register address   (0x2C0)
    CONFIG_FLOW_CTRL_ADD  = 9'b011000000;

    // Receiver configuration register address       (0x240)
    RECEIVER_ADD          = 9'b001000000;

    // Transmitter configuration register address    (0x280)
    TRANSMITTER_ADD       = 9'b010000000;

    // Transmitter configuration register address    (0x300)
    EMAC_CONFIG_ADD       = 9'b100000000;

    // Unicast Word 0 configuration register address (0x380)
    CONFIG_UNI0_CTRL_ADD  = 9'b110000000;

    // Unicast Word 1 configuration register address (0x384)
    CONFIG_UNI1_CTRL_ADD  = 9'b110000100;

    // Address Filter configuration register address (0x390)
    CONFIG_ADDR_CTRL_ADD  = 9'b110010000;

  end

  //----------------------------------------------------------------------------
  // types to support frame data
  //----------------------------------------------------------------------------

   frame_typ frame0();
   frame_typ frame1();
   frame_typ frame2();
   frame_typ frame3();

   frame_typ rx_stimulus_working_frame();
   frame_typ tx_monitor_working_frame();


  //----------------------------------------------------------------------------
  // Stimulus - Frame data
  //----------------------------------------------------------------------------
  // The following constant holds the stimulus for the testbench. It is
  // an ordered array of frames, with frame 0 the first to be injected
  // into the core transmit interface by the testbench.
  //----------------------------------------------------------------------------
  initial
  begin
    //-----------
    // Frame 0
    //-----------
    frame0.data[0]  = 8'hDA;  frame0.valid[0]  = 1'b1;  frame0.error[0]  = 1'b0; // Destination Address (DA)
    frame0.data[1]  = 8'h02;  frame0.valid[1]  = 1'b1;  frame0.error[1]  = 1'b0;
    frame0.data[2]  = 8'h03;  frame0.valid[2]  = 1'b1;  frame0.error[2]  = 1'b0;
    frame0.data[3]  = 8'h04;  frame0.valid[3]  = 1'b1;  frame0.error[3]  = 1'b0;
    frame0.data[4]  = 8'h05;  frame0.valid[4]  = 1'b1;  frame0.error[4]  = 1'b0;
    frame0.data[5]  = 8'h06;  frame0.valid[5]  = 1'b1;  frame0.error[5]  = 1'b0;
    frame0.data[6]  = 8'h5A;  frame0.valid[6]  = 1'b1;  frame0.error[6]  = 1'b0; // Source Address  (5A)
    frame0.data[7]  = 8'h02;  frame0.valid[7]  = 1'b1;  frame0.error[7]  = 1'b0;
    frame0.data[8]  = 8'h03;  frame0.valid[8]  = 1'b1;  frame0.error[8]  = 1'b0;
    frame0.data[9]  = 8'h04;  frame0.valid[9]  = 1'b1;  frame0.error[9]  = 1'b0;
    frame0.data[10] = 8'h05;  frame0.valid[10] = 1'b1;  frame0.error[10] = 1'b0;
    frame0.data[11] = 8'h06;  frame0.valid[11] = 1'b1;  frame0.error[11] = 1'b0;
    frame0.data[12] = 8'h00;  frame0.valid[12] = 1'b1;  frame0.error[12] = 1'b0;
    frame0.data[13] = 8'h2E;  frame0.valid[13] = 1'b1;  frame0.error[13] = 1'b0; // Length/Type = Length = 46
    frame0.data[14] = 8'h01;  frame0.valid[14] = 1'b1;  frame0.error[14] = 1'b0;
    frame0.data[15] = 8'h02;  frame0.valid[15] = 1'b1;  frame0.error[15] = 1'b0;
    frame0.data[16] = 8'h03;  frame0.valid[16] = 1'b1;  frame0.error[16] = 1'b0;
    frame0.data[17] = 8'h04;  frame0.valid[17] = 1'b1;  frame0.error[17] = 1'b0;
    frame0.data[18] = 8'h05;  frame0.valid[18] = 1'b1;  frame0.error[18] = 1'b0;
    frame0.data[19] = 8'h06;  frame0.valid[19] = 1'b1;  frame0.error[19] = 1'b0;
    frame0.data[20] = 8'h07;  frame0.valid[20] = 1'b1;  frame0.error[20] = 1'b0;
    frame0.data[21] = 8'h08;  frame0.valid[21] = 1'b1;  frame0.error[21] = 1'b0;
    frame0.data[22] = 8'h09;  frame0.valid[22] = 1'b1;  frame0.error[22] = 1'b0;
    frame0.data[23] = 8'h0A;  frame0.valid[23] = 1'b1;  frame0.error[23] = 1'b0;
    frame0.data[24] = 8'h0B;  frame0.valid[24] = 1'b1;  frame0.error[24] = 1'b0;
    frame0.data[25] = 8'h0C;  frame0.valid[25] = 1'b1;  frame0.error[25] = 1'b0;
    frame0.data[26] = 8'h0D;  frame0.valid[26] = 1'b1;  frame0.error[26] = 1'b0;
    frame0.data[27] = 8'h0E;  frame0.valid[27] = 1'b1;  frame0.error[27] = 1'b0;
    frame0.data[28] = 8'h0F;  frame0.valid[28] = 1'b1;  frame0.error[28] = 1'b0;
    frame0.data[29] = 8'h10;  frame0.valid[29] = 1'b1;  frame0.error[29] = 1'b0;
    frame0.data[30] = 8'h11;  frame0.valid[30] = 1'b1;  frame0.error[30] = 1'b0;
    frame0.data[31] = 8'h12;  frame0.valid[31] = 1'b1;  frame0.error[31] = 1'b0;
    frame0.data[32] = 8'h13;  frame0.valid[32] = 1'b1;  frame0.error[32] = 1'b0;
    frame0.data[33] = 8'h14;  frame0.valid[33] = 1'b1;  frame0.error[33] = 1'b0;
    frame0.data[34] = 8'h15;  frame0.valid[34] = 1'b1;  frame0.error[34] = 1'b0;
    frame0.data[35] = 8'h16;  frame0.valid[35] = 1'b1;  frame0.error[35] = 1'b0;
    frame0.data[36] = 8'h17;  frame0.valid[36] = 1'b1;  frame0.error[36] = 1'b0;
    frame0.data[37] = 8'h18;  frame0.valid[37] = 1'b1;  frame0.error[37] = 1'b0;
    frame0.data[38] = 8'h19;  frame0.valid[38] = 1'b1;  frame0.error[38] = 1'b0;
    frame0.data[39] = 8'h1A;  frame0.valid[39] = 1'b1;  frame0.error[39] = 1'b0;
    frame0.data[40] = 8'h1B;  frame0.valid[40] = 1'b1;  frame0.error[40] = 1'b0;
    frame0.data[41] = 8'h1C;  frame0.valid[41] = 1'b1;  frame0.error[41] = 1'b0;
    frame0.data[42] = 8'h1D;  frame0.valid[42] = 1'b1;  frame0.error[42] = 1'b0;
    frame0.data[43] = 8'h1E;  frame0.valid[43] = 1'b1;  frame0.error[43] = 1'b0;
    frame0.data[44] = 8'h1F;  frame0.valid[44] = 1'b1;  frame0.error[44] = 1'b0;
    frame0.data[45] = 8'h20;  frame0.valid[45] = 1'b1;  frame0.error[45] = 1'b0;
    frame0.data[46] = 8'h21;  frame0.valid[46] = 1'b1;  frame0.error[46] = 1'b0;
    frame0.data[47] = 8'h22;  frame0.valid[47] = 1'b1;  frame0.error[47] = 1'b0;
    frame0.data[48] = 8'h23;  frame0.valid[48] = 1'b1;  frame0.error[48] = 1'b0;
    frame0.data[49] = 8'h24;  frame0.valid[49] = 1'b1;  frame0.error[49] = 1'b0;
    frame0.data[50] = 8'h25;  frame0.valid[50] = 1'b1;  frame0.error[50] = 1'b0;
    frame0.data[51] = 8'h26;  frame0.valid[51] = 1'b1;  frame0.error[51] = 1'b0;
    frame0.data[52] = 8'h27;  frame0.valid[52] = 1'b1;  frame0.error[52] = 1'b0;
    frame0.data[53] = 8'h28;  frame0.valid[53] = 1'b1;  frame0.error[53] = 1'b0;
    frame0.data[54] = 8'h29;  frame0.valid[54] = 1'b1;  frame0.error[54] = 1'b0;
    frame0.data[55] = 8'h2A;  frame0.valid[55] = 1'b1;  frame0.error[55] = 1'b0;
    frame0.data[56] = 8'h2B;  frame0.valid[56] = 1'b1;  frame0.error[56] = 1'b0;
    frame0.data[57] = 8'h2C;  frame0.valid[57] = 1'b1;  frame0.error[57] = 1'b0;
    frame0.data[58] = 8'h2D;  frame0.valid[58] = 1'b1;  frame0.error[58] = 1'b0;
    frame0.data[59] = 8'h2E;  frame0.valid[59] = 1'b1;  frame0.error[59] = 1'b0;  // 46th Byte of Data
    // unused
    frame0.data[60] = 8'h00;  frame0.valid[60] = 1'b0;  frame0.error[60] = 1'b0;
    frame0.data[61] = 8'h00;  frame0.valid[61] = 1'b0;  frame0.error[61] = 1'b0;

    // No error in this frame
    frame0.bad_frame  = 1'b0;


    //-----------
    // Frame 1
    //-----------
    frame1.data[0]  = 8'hDA;  frame1.valid[0]  = 1'b1;  frame1.error[0]  = 1'b0; // Destination Address (DA)
    frame1.data[1]  = 8'h02;  frame1.valid[1]  = 1'b1;  frame1.error[1]  = 1'b0;
    frame1.data[2]  = 8'h00;  frame1.valid[2]  = 1'b1;  frame1.error[2]  = 1'b0;
    frame1.data[3]  = 8'h04;  frame1.valid[3]  = 1'b1;  frame1.error[3]  = 1'b0;
    frame1.data[4]  = 8'h05;  frame1.valid[4]  = 1'b1;  frame1.error[4]  = 1'b0;
    frame1.data[5]  = 8'h06;  frame1.valid[5]  = 1'b1;  frame1.error[5]  = 1'b0;
    frame1.data[6]  = 8'h5A;  frame1.valid[6]  = 1'b1;  frame1.error[6]  = 1'b0; // Source Address  (5A)
    frame1.data[7]  = 8'h02;  frame1.valid[7]  = 1'b1;  frame1.error[7]  = 1'b0;
    frame1.data[8]  = 8'h03;  frame1.valid[8]  = 1'b1;  frame1.error[8]  = 1'b0;
    frame1.data[9]  = 8'h04;  frame1.valid[9]  = 1'b1;  frame1.error[9]  = 1'b0;
    frame1.data[10] = 8'h05;  frame1.valid[10] = 1'b1;  frame1.error[10] = 1'b0;
    frame1.data[11] = 8'h06;  frame1.valid[11] = 1'b1;  frame1.error[11] = 1'b0;
    frame1.data[12] = 8'h80;  frame1.valid[12] = 1'b1;  frame1.error[12] = 1'b0; // Length/Type = Type = 8000
    frame1.data[13] = 8'h00;  frame1.valid[13] = 1'b1;  frame1.error[13] = 1'b0;
    frame1.data[14] = 8'h01;  frame1.valid[14] = 1'b1;  frame1.error[14] = 1'b0;
    frame1.data[15] = 8'h02;  frame1.valid[15] = 1'b1;  frame1.error[15] = 1'b0;
    frame1.data[16] = 8'h03;  frame1.valid[16] = 1'b1;  frame1.error[16] = 1'b0;
    frame1.data[17] = 8'h04;  frame1.valid[17] = 1'b1;  frame1.error[17] = 1'b0;
    frame1.data[18] = 8'h05;  frame1.valid[18] = 1'b1;  frame1.error[18] = 1'b0;
    frame1.data[19] = 8'h06;  frame1.valid[19] = 1'b1;  frame1.error[19] = 1'b0;
    frame1.data[20] = 8'h07;  frame1.valid[20] = 1'b1;  frame1.error[20] = 1'b0;
    frame1.data[21] = 8'h08;  frame1.valid[21] = 1'b1;  frame1.error[21] = 1'b0;
    frame1.data[22] = 8'h09;  frame1.valid[22] = 1'b1;  frame1.error[22] = 1'b0;
    frame1.data[23] = 8'h0A;  frame1.valid[23] = 1'b1;  frame1.error[23] = 1'b0;
    frame1.data[24] = 8'h0B;  frame1.valid[24] = 1'b1;  frame1.error[24] = 1'b0;
    frame1.data[25] = 8'h0C;  frame1.valid[25] = 1'b1;  frame1.error[25] = 1'b0;
    frame1.data[26] = 8'h0D;  frame1.valid[26] = 1'b1;  frame1.error[26] = 1'b0;
    frame1.data[27] = 8'h0E;  frame1.valid[27] = 1'b1;  frame1.error[27] = 1'b0;
    frame1.data[28] = 8'h0F;  frame1.valid[28] = 1'b1;  frame1.error[28] = 1'b0;
    frame1.data[29] = 8'h10;  frame1.valid[29] = 1'b1;  frame1.error[29] = 1'b0;
    frame1.data[30] = 8'h11;  frame1.valid[30] = 1'b1;  frame1.error[30] = 1'b0;
    frame1.data[31] = 8'h12;  frame1.valid[31] = 1'b1;  frame1.error[31] = 1'b0;
    frame1.data[32] = 8'h13;  frame1.valid[32] = 1'b1;  frame1.error[32] = 1'b0;
    frame1.data[33] = 8'h14;  frame1.valid[33] = 1'b1;  frame1.error[33] = 1'b0;
    frame1.data[34] = 8'h15;  frame1.valid[34] = 1'b1;  frame1.error[34] = 1'b0;
    frame1.data[35] = 8'h16;  frame1.valid[35] = 1'b1;  frame1.error[35] = 1'b0;
    frame1.data[36] = 8'h17;  frame1.valid[36] = 1'b1;  frame1.error[36] = 1'b0;
    frame1.data[37] = 8'h18;  frame1.valid[37] = 1'b1;  frame1.error[37] = 1'b0;
    frame1.data[38] = 8'h19;  frame1.valid[38] = 1'b1;  frame1.error[38] = 1'b0;
    frame1.data[39] = 8'h1A;  frame1.valid[39] = 1'b1;  frame1.error[39] = 1'b0;
    frame1.data[40] = 8'h1B;  frame1.valid[40] = 1'b1;  frame1.error[40] = 1'b0;
    frame1.data[41] = 8'h1C;  frame1.valid[41] = 1'b1;  frame1.error[41] = 1'b0;
    frame1.data[42] = 8'h1D;  frame1.valid[42] = 1'b1;  frame1.error[42] = 1'b0;
    frame1.data[43] = 8'h1E;  frame1.valid[43] = 1'b1;  frame1.error[43] = 1'b0;
    frame1.data[44] = 8'h1F;  frame1.valid[44] = 1'b1;  frame1.error[44] = 1'b0;
    frame1.data[45] = 8'h20;  frame1.valid[45] = 1'b1;  frame1.error[45] = 1'b0;
    frame1.data[46] = 8'h21;  frame1.valid[46] = 1'b1;  frame1.error[46] = 1'b0;
    frame1.data[47] = 8'h22;  frame1.valid[47] = 1'b1;  frame1.error[47] = 1'b0;
    frame1.data[48] = 8'h23;  frame1.valid[48] = 1'b1;  frame1.error[48] = 1'b0;
    frame1.data[49] = 8'h24;  frame1.valid[49] = 1'b1;  frame1.error[49] = 1'b0;
    frame1.data[50] = 8'h25;  frame1.valid[50] = 1'b1;  frame1.error[50] = 1'b0;
    frame1.data[51] = 8'h26;  frame1.valid[51] = 1'b1;  frame1.error[51] = 1'b0;
    frame1.data[52] = 8'h27;  frame1.valid[52] = 1'b1;  frame1.error[52] = 1'b0;
    frame1.data[53] = 8'h28;  frame1.valid[53] = 1'b1;  frame1.error[53] = 1'b0;
    frame1.data[54] = 8'h29;  frame1.valid[54] = 1'b1;  frame1.error[54] = 1'b0;
    frame1.data[55] = 8'h2A;  frame1.valid[55] = 1'b1;  frame1.error[55] = 1'b0;
    frame1.data[56] = 8'h2B;  frame1.valid[56] = 1'b1;  frame1.error[56] = 1'b0;
    frame1.data[57] = 8'h2C;  frame1.valid[57] = 1'b1;  frame1.error[57] = 1'b0;
    frame1.data[58] = 8'h2D;  frame1.valid[58] = 1'b1;  frame1.error[58] = 1'b0;
    frame1.data[59] = 8'h2E;  frame1.valid[59] = 1'b1;  frame1.error[59] = 1'b0;
    frame1.data[60] = 8'h2F;  frame1.valid[60] = 1'b1;  frame1.error[60] = 1'b0; // 47th Data byte
    // unused
    frame1.data[61] = 8'h00;  frame1.valid[61] = 1'b0;  frame1.error[61] = 1'b0;

    // No error in this frame
    frame1.bad_frame  = 1'b0;


    //-----------
    // Frame 2
    //-----------
    frame2.data[0]  = 8'hDA;  frame2.valid[0]  = 1'b1;  frame2.error[0]  = 1'b0; // Destination Address (DA)
    frame2.data[1]  = 8'h02;  frame2.valid[1]  = 1'b1;  frame2.error[1]  = 1'b0;
    frame2.data[2]  = 8'h03;  frame2.valid[2]  = 1'b1;  frame2.error[2]  = 1'b0;
    frame2.data[3]  = 8'h04;  frame2.valid[3]  = 1'b1;  frame2.error[3]  = 1'b0;
    frame2.data[4]  = 8'h05;  frame2.valid[4]  = 1'b1;  frame2.error[4]  = 1'b0;
    frame2.data[5]  = 8'h06;  frame2.valid[5]  = 1'b1;  frame2.error[5]  = 1'b0;
    frame2.data[6]  = 8'h5A;  frame2.valid[6]  = 1'b1;  frame2.error[6]  = 1'b0; // Source Address  (5A)
    frame2.data[7]  = 8'h02;  frame2.valid[7]  = 1'b1;  frame2.error[7]  = 1'b0;
    frame2.data[8]  = 8'h03;  frame2.valid[8]  = 1'b1;  frame2.error[8]  = 1'b0;
    frame2.data[9]  = 8'h04;  frame2.valid[9]  = 1'b1;  frame2.error[9]  = 1'b0;
    frame2.data[10] = 8'h05;  frame2.valid[10] = 1'b1;  frame2.error[10] = 1'b0;
    frame2.data[11] = 8'h06;  frame2.valid[11] = 1'b1;  frame2.error[11] = 1'b0;
    frame2.data[12] = 8'h00;  frame2.valid[12] = 1'b1;  frame2.error[12] = 1'b0;
    frame2.data[13] = 8'h2E;  frame2.valid[13] = 1'b1;  frame2.error[13] = 1'b0; // Length/Type = Length = 46
    frame2.data[14] = 8'h01;  frame2.valid[14] = 1'b1;  frame2.error[14] = 1'b0;
    frame2.data[15] = 8'h02;  frame2.valid[15] = 1'b1;  frame2.error[15] = 1'b0;
    frame2.data[16] = 8'h03;  frame2.valid[16] = 1'b1;  frame2.error[16] = 1'b0;
    frame2.data[17] = 8'h00;  frame2.valid[17] = 1'b1;  frame2.error[17] = 1'b0; // Underrun this frame
    frame2.data[18] = 8'h00;  frame2.valid[18] = 1'b1;  frame2.error[18] = 1'b0;
    frame2.data[19] = 8'h00;  frame2.valid[19] = 1'b1;  frame2.error[19] = 1'b0;
    frame2.data[20] = 8'h00;  frame2.valid[20] = 1'b1;  frame2.error[20] = 1'b0;
    frame2.data[21] = 8'h00;  frame2.valid[21] = 1'b1;  frame2.error[21] = 1'b0;
    frame2.data[22] = 8'h00;  frame2.valid[22] = 1'b1;  frame2.error[22] = 1'b0;
    frame2.data[23] = 8'h00;  frame2.valid[23] = 1'b1;  frame2.error[23] = 1'b1; // Error asserted
    frame2.data[24] = 8'h00;  frame2.valid[24] = 1'b1;  frame2.error[24] = 1'b0;
    frame2.data[25] = 8'h00;  frame2.valid[25] = 1'b1;  frame2.error[25] = 1'b0;
    frame2.data[26] = 8'h00;  frame2.valid[26] = 1'b1;  frame2.error[26] = 1'b0;
    frame2.data[27] = 8'h00;  frame2.valid[27] = 1'b1;  frame2.error[27] = 1'b0;
    frame2.data[28] = 8'h00;  frame2.valid[28] = 1'b1;  frame2.error[28] = 1'b0;
    frame2.data[29] = 8'h00;  frame2.valid[29] = 1'b1;  frame2.error[29] = 1'b0;
    frame2.data[30] = 8'h00;  frame2.valid[30] = 1'b1;  frame2.error[30] = 1'b0;
    frame2.data[31] = 8'h00;  frame2.valid[31] = 1'b1;  frame2.error[31] = 1'b0;
    frame2.data[32] = 8'h00;  frame2.valid[32] = 1'b1;  frame2.error[32] = 1'b0;
    frame2.data[33] = 8'h00;  frame2.valid[33] = 1'b1;  frame2.error[33] = 1'b0;
    frame2.data[34] = 8'h00;  frame2.valid[34] = 1'b1;  frame2.error[34] = 1'b0;
    frame2.data[35] = 8'h00;  frame2.valid[35] = 1'b1;  frame2.error[35] = 1'b0;
    frame2.data[36] = 8'h00;  frame2.valid[36] = 1'b1;  frame2.error[36] = 1'b0;
    frame2.data[37] = 8'h00;  frame2.valid[37] = 1'b1;  frame2.error[37] = 1'b0;
    frame2.data[38] = 8'h00;  frame2.valid[38] = 1'b1;  frame2.error[38] = 1'b0;
    frame2.data[39] = 8'h00;  frame2.valid[39] = 1'b1;  frame2.error[39] = 1'b0;
    frame2.data[40] = 8'h00;  frame2.valid[40] = 1'b1;  frame2.error[40] = 1'b0;
    frame2.data[41] = 8'h00;  frame2.valid[41] = 1'b1;  frame2.error[41] = 1'b0;
    frame2.data[42] = 8'h00;  frame2.valid[42] = 1'b1;  frame2.error[42] = 1'b0;
    frame2.data[43] = 8'h00;  frame2.valid[43] = 1'b1;  frame2.error[43] = 1'b0;
    frame2.data[44] = 8'h00;  frame2.valid[44] = 1'b1;  frame2.error[44] = 1'b0;
    frame2.data[45] = 8'h00;  frame2.valid[45] = 1'b1;  frame2.error[45] = 1'b0;
    frame2.data[46] = 8'h00;  frame2.valid[46] = 1'b1;  frame2.error[46] = 1'b0;
    frame2.data[47] = 8'h00;  frame2.valid[47] = 1'b1;  frame2.error[47] = 1'b0;
    frame2.data[48] = 8'h00;  frame2.valid[48] = 1'b1;  frame2.error[48] = 1'b0;
    frame2.data[49] = 8'h00;  frame2.valid[49] = 1'b1;  frame2.error[49] = 1'b0;
    frame2.data[50] = 8'h00;  frame2.valid[50] = 1'b1;  frame2.error[50] = 1'b0;
    frame2.data[51] = 8'h00;  frame2.valid[51] = 1'b1;  frame2.error[51] = 1'b0;
    frame2.data[52] = 8'h00;  frame2.valid[52] = 1'b1;  frame2.error[52] = 1'b0;
    frame2.data[53] = 8'h00;  frame2.valid[53] = 1'b1;  frame2.error[53] = 1'b0;
    frame2.data[54] = 8'h00;  frame2.valid[54] = 1'b1;  frame2.error[54] = 1'b0;
    frame2.data[55] = 8'h00;  frame2.valid[55] = 1'b1;  frame2.error[55] = 1'b0;
    frame2.data[56] = 8'h00;  frame2.valid[56] = 1'b1;  frame2.error[56] = 1'b0;
    frame2.data[57] = 8'h00;  frame2.valid[57] = 1'b1;  frame2.error[57] = 1'b0;
    frame2.data[58] = 8'h00;  frame2.valid[58] = 1'b1;  frame2.error[58] = 1'b0;
    frame2.data[59] = 8'h00;  frame2.valid[59] = 1'b1;  frame2.error[59] = 1'b0;
    // unused
    frame2.data[60] = 8'h00;  frame2.valid[60] = 1'b0;  frame2.error[60] = 1'b0;
    frame2.data[61] = 8'h00;  frame2.valid[61] = 1'b0;  frame2.error[61] = 1'b0;

    // Error this frame
    frame2.bad_frame  = 1'b1;


    //-----------
    // Frame 3
    //-----------
    frame3.data[0]  = 8'hDA;  frame3.valid[0]  = 1'b1;  frame3.error[0]  = 1'b0; // Destination Address (DA)
    frame3.data[1]  = 8'h02;  frame3.valid[1]  = 1'b1;  frame3.error[1]  = 1'b0;
    frame3.data[2]  = 8'h03;  frame3.valid[2]  = 1'b1;  frame3.error[2]  = 1'b0;
    frame3.data[3]  = 8'h04;  frame3.valid[3]  = 1'b1;  frame3.error[3]  = 1'b0;
    frame3.data[4]  = 8'h05;  frame3.valid[4]  = 1'b1;  frame3.error[4]  = 1'b0;
    frame3.data[5]  = 8'h06;  frame3.valid[5]  = 1'b1;  frame3.error[5]  = 1'b0;
    frame3.data[6]  = 8'h5A;  frame3.valid[6]  = 1'b1;  frame3.error[6]  = 1'b0; // Source Address  (5A)
    frame3.data[7]  = 8'h02;  frame3.valid[7]  = 1'b1;  frame3.error[7]  = 1'b0;
    frame3.data[8]  = 8'h03;  frame3.valid[8]  = 1'b1;  frame3.error[8]  = 1'b0;
    frame3.data[9]  = 8'h04;  frame3.valid[9]  = 1'b1;  frame3.error[9]  = 1'b0;
    frame3.data[10] = 8'h05;  frame3.valid[10] = 1'b1;  frame3.error[10] = 1'b0;
    frame3.data[11] = 8'h06;  frame3.valid[11] = 1'b1;  frame3.error[11] = 1'b0;
    frame3.data[12] = 8'h00;  frame3.valid[12] = 1'b1;  frame3.error[12] = 1'b0;
    frame3.data[13] = 8'h03;  frame3.valid[13] = 1'b1;  frame3.error[13] = 1'b0; // Length/Type = Length = 03
    frame3.data[14] = 8'h01;  frame3.valid[14] = 1'b1;  frame3.error[14] = 1'b0; // Therefore padding is required
    frame3.data[15] = 8'h02;  frame3.valid[15] = 1'b1;  frame3.error[15] = 1'b0;
    frame3.data[16] = 8'h03;  frame3.valid[16] = 1'b1;  frame3.error[16] = 1'b0;
    frame3.data[17] = 8'h00;  frame3.valid[17] = 1'b1;  frame3.error[17] = 1'b0; // Padding starts here
    frame3.data[18] = 8'h00;  frame3.valid[18] = 1'b1;  frame3.error[18] = 1'b0;
    frame3.data[19] = 8'h00;  frame3.valid[19] = 1'b1;  frame3.error[19] = 1'b0;
    frame3.data[20] = 8'h00;  frame3.valid[20] = 1'b1;  frame3.error[20] = 1'b0;
    frame3.data[21] = 8'h00;  frame3.valid[21] = 1'b1;  frame3.error[21] = 1'b0;
    frame3.data[22] = 8'h00;  frame3.valid[22] = 1'b1;  frame3.error[22] = 1'b0;
    frame3.data[23] = 8'h00;  frame3.valid[23] = 1'b1;  frame3.error[23] = 1'b0;
    frame3.data[24] = 8'h00;  frame3.valid[24] = 1'b1;  frame3.error[24] = 1'b0;
    frame3.data[25] = 8'h00;  frame3.valid[25] = 1'b1;  frame3.error[25] = 1'b0;
    frame3.data[26] = 8'h00;  frame3.valid[26] = 1'b1;  frame3.error[26] = 1'b0;
    frame3.data[27] = 8'h00;  frame3.valid[27] = 1'b1;  frame3.error[27] = 1'b0;
    frame3.data[28] = 8'h00;  frame3.valid[28] = 1'b1;  frame3.error[28] = 1'b0;
    frame3.data[29] = 8'h00;  frame3.valid[29] = 1'b1;  frame3.error[29] = 1'b0;
    frame3.data[30] = 8'h00;  frame3.valid[30] = 1'b1;  frame3.error[30] = 1'b0;
    frame3.data[31] = 8'h00;  frame3.valid[31] = 1'b1;  frame3.error[31] = 1'b0;
    frame3.data[32] = 8'h00;  frame3.valid[32] = 1'b1;  frame3.error[32] = 1'b0;
    frame3.data[33] = 8'h00;  frame3.valid[33] = 1'b1;  frame3.error[33] = 1'b0;
    frame3.data[34] = 8'h00;  frame3.valid[34] = 1'b1;  frame3.error[34] = 1'b0;
    frame3.data[35] = 8'h00;  frame3.valid[35] = 1'b1;  frame3.error[35] = 1'b0;
    frame3.data[36] = 8'h00;  frame3.valid[36] = 1'b1;  frame3.error[36] = 1'b0;
    frame3.data[37] = 8'h00;  frame3.valid[37] = 1'b1;  frame3.error[37] = 1'b0;
    frame3.data[38] = 8'h00;  frame3.valid[38] = 1'b1;  frame3.error[38] = 1'b0;
    frame3.data[39] = 8'h00;  frame3.valid[39] = 1'b1;  frame3.error[39] = 1'b0;
    frame3.data[40] = 8'h00;  frame3.valid[40] = 1'b1;  frame3.error[40] = 1'b0;
    frame3.data[41] = 8'h00;  frame3.valid[41] = 1'b1;  frame3.error[41] = 1'b0;
    frame3.data[42] = 8'h00;  frame3.valid[42] = 1'b1;  frame3.error[42] = 1'b0;
    frame3.data[43] = 8'h00;  frame3.valid[43] = 1'b1;  frame3.error[43] = 1'b0;
    frame3.data[44] = 8'h00;  frame3.valid[44] = 1'b1;  frame3.error[44] = 1'b0;
    frame3.data[45] = 8'h00;  frame3.valid[45] = 1'b1;  frame3.error[45] = 1'b0;
    frame3.data[46] = 8'h00;  frame3.valid[46] = 1'b1;  frame3.error[46] = 1'b0;
    frame3.data[47] = 8'h00;  frame3.valid[47] = 1'b1;  frame3.error[47] = 1'b0;
    frame3.data[48] = 8'h00;  frame3.valid[48] = 1'b1;  frame3.error[48] = 1'b0;
    frame3.data[49] = 8'h00;  frame3.valid[49] = 1'b1;  frame3.error[49] = 1'b0;
    frame3.data[50] = 8'h00;  frame3.valid[50] = 1'b1;  frame3.error[50] = 1'b0;
    frame3.data[51] = 8'h00;  frame3.valid[51] = 1'b1;  frame3.error[51] = 1'b0;
    frame3.data[52] = 8'h00;  frame3.valid[52] = 1'b1;  frame3.error[52] = 1'b0;
    frame3.data[53] = 8'h00;  frame3.valid[53] = 1'b1;  frame3.error[53] = 1'b0;
    frame3.data[54] = 8'h00;  frame3.valid[54] = 1'b1;  frame3.error[54] = 1'b0;
    frame3.data[55] = 8'h00;  frame3.valid[55] = 1'b1;  frame3.error[55] = 1'b0;
    frame3.data[56] = 8'h00;  frame3.valid[56] = 1'b1;  frame3.error[56] = 1'b0;
    frame3.data[57] = 8'h00;  frame3.valid[57] = 1'b1;  frame3.error[57] = 1'b0;
    frame3.data[58] = 8'h00;  frame3.valid[58] = 1'b1;  frame3.error[58] = 1'b0;
    frame3.data[59] = 8'h00;  frame3.valid[59] = 1'b1;  frame3.error[59] = 1'b0;
    // unused
    frame3.data[60] = 8'h00;  frame3.valid[60] = 1'b0;  frame3.error[60] = 1'b0;
    frame3.data[61] = 8'h00;  frame3.valid[61] = 1'b0;  frame3.error[61] = 1'b0;

    // No error in this frame
    frame3.bad_frame  = 1'b0;

  end


  //--------------------------------------------------------------------
  // CRC engine
  //--------------------------------------------------------------------
  task calc_crc;
    input  [7:0]  data;
    inout  [31:0] fcs;

    reg [31:0] crc;
    reg        crc_feedback;
    integer    I;
  begin

    crc = ~ fcs;

    for (I = 0; I < 8; I = I + 1)
    begin
      crc_feedback = crc[0] ^ data[I];

      crc[0]       = crc[1];
      crc[1]       = crc[2];
      crc[2]       = crc[3];
      crc[3]       = crc[4];
      crc[4]       = crc[5];
      crc[5]       = crc[6]  ^ crc_feedback;
      crc[6]       = crc[7];
      crc[7]       = crc[8];
      crc[8]       = crc[9]  ^ crc_feedback;
      crc[9]       = crc[10] ^ crc_feedback;
      crc[10]      = crc[11];
      crc[11]      = crc[12];
      crc[12]      = crc[13];
      crc[13]      = crc[14];
      crc[14]      = crc[15];
      crc[15]      = crc[16] ^ crc_feedback;
      crc[16]      = crc[17];
      crc[17]      = crc[18];
      crc[18]      = crc[19];
      crc[19]      = crc[20] ^ crc_feedback;
      crc[20]      = crc[21] ^ crc_feedback;
      crc[21]      = crc[22] ^ crc_feedback;
      crc[22]      = crc[23];
      crc[23]      = crc[24] ^ crc_feedback;
      crc[24]      = crc[25] ^ crc_feedback;
      crc[25]      = crc[26];
      crc[26]      = crc[27] ^ crc_feedback;
      crc[27]      = crc[28] ^ crc_feedback;
      crc[28]      = crc[29];
      crc[29]      = crc[30] ^ crc_feedback;
      crc[30]      = crc[31] ^ crc_feedback;
      crc[31]      =           crc_feedback;
    end

    // return the CRC result
    fcs = ~ crc;

    end
  endtask // calc_crc




  //----------------------------------------------------------------------------
  // Test Bench signals and constants
  //----------------------------------------------------------------------------

  // Delay to provide setup and hold timing at the GMII/RGMII.
  parameter dly = 5800;  // has to be valid from 6ns to 8ns

  // testbench signals
  reg         reset;
  reg         refclk;
  wire        tx_clk;
  reg  [7:0]  tx_ifg_delay;
  wire        tx_statistics_vector;
  wire        tx_statistics_valid;
  wire        rx_clk;
  wire        rx_statistics_vector;
  wire        rx_statistics_valid;
  wire        pause_val;
  wire        pause_req;
  reg         host_clk;
  reg  [1:0]  host_opcode;
  reg  [9:0]  host_addr;
  reg  [31:0] host_wr_data;
  wire [31:0] host_rd_data;
  reg         host_miim_sel;
  reg         host_req;
  wire        host_miim_rdy;
  wire        mdc;
  wire        mdio;
  reg  [5:0]  mdio_count;
  reg         last_mdio;
  reg         mdio_read;
  reg         mdio_addr;
  reg         mdio_fail;
  reg [31:0]  rd_data_value;
  wire        mii_tx_en;
  wire        mii_tx_er;
  wire [3:0]  mii_txd;
  wire        mii_rx_clk;
  reg         mii_rx_dv;
  reg         mii_rx_er;
  reg  [3:0]  mii_rxd;
  reg         mii_tx_clk100;
  reg         mii_tx_clk10;
  reg         mii_tx_clk;
  wire        gmii_col;
  wire        gmii_crs;

  // testbench control semaphores
  reg [1:0] current_speed;
  reg  tx_monitor_finished_10M;
  reg  tx_monitor_finished_100M;
  reg  management_config_finished;

  wire test_half_duplex;


  assign test_half_duplex = 1'b0;

/*
  //----------------------------------------------------------------------------
  // Wire up Device Under Test
  //----------------------------------------------------------------------------
  tri_mode_eth_mac_v4_6_example_design dut
    (
      // asynchronous reset
      .reset                (reset),


      // Client Receiver Statistics Interface (serialised to reduce IO for the example design)
      .rx_clk               (rx_clk),
      .rx_statistics_vector (rx_statistics_vector),
      .rx_statistics_valid  (rx_statistics_valid),

      // Client Transmitter Statistics Interface (serialised to reduce IO for the example design)
      .tx_clk               (tx_clk),
      .tx_statistics_vector (tx_statistics_vector),
      .tx_statistics_valid  (tx_statistics_valid),

      //-- Flow Control (serialised to reduce IO for the example design)
      .pause_req            (pause_req),
      .pause_val            (pause_val),

      // MII Interface
      .mii_txd              (mii_txd),
      .mii_tx_en            (mii_tx_en),
      .mii_tx_er            (mii_tx_er),
      .mii_rxd              (mii_rxd),
      .mii_rx_dv            (mii_rx_dv),
      .mii_rx_er            (mii_rx_er),
      .mii_rx_clk           (mii_rx_clk),
      .mii_col              (mii_col),
      .mii_crs              (mii_crs),
      .mii_tx_clk           (mii_tx_clk),

      // MDIO Interface
      .mdc                  (mdc),
      .mdio                 (mdio),

      // Host Interface
      .host_clk             (host_clk),
      .host_opcode          (host_opcode),
      .host_addr            (host_addr),
      .host_wr_data         (host_wr_data),
      .host_rd_data         (host_rd_data),
      .host_miim_sel        (host_miim_sel),
      .host_req             (host_req),
      .host_miim_rdy        (host_miim_rdy)
   );
*/

/*
eth_mac_top 
eth_mac_top_inst0
( 
    .reset         (reset),

    .mtx_clk_pad_i (mii_tx_clk) ,
    .mtxd_pad_o    (mii_txd) ,   
    .mtxen_pad_o   (mii_tx_en) ,  
    .mtxerr_pad_o  (mii_tx_er) , 
    
    .mrx_clk_pad_i (mii_rx_clk) ,
    .mrxd_pad_i    (mii_rxd) ,   
    .mrxdv_pad_i   (mii_rx_dv) ,  
    .mrxerr_pad_i  (mii_rx_er) , 
    
    .mcoll_pad_i   (mii_col) ,  
    .mcrs_pad_i    (mii_crs) ,   
    
    .mdc_pad_o     (mdc) ,    
    .md_pad_i      () ,     
    .md_pad_o      () ,     
    .md_padoe_o    () ,   
    
    .int_o( )          
);
*/
wire[15:0] mrx_dma_addr  ;
wire       mrx_dma_req   ;
wire[31:0] mrx_dma_wdata ;
wire       mrx_dma_we    ;
wire       mrx_dma_gnt   ;
wire[31:0] mrx_dma_rdata ;
wire       mrx_dma_rvalid;

wire[15:0] mtx_dma_addr  ;
wire       mtx_dma_req   ;
wire[31:0] mtx_dma_wdata ;
wire       mtx_dma_we    ;
wire       mtx_dma_gnt   ;
wire[31:0] mtx_dma_rdata ;
wire       mtx_dma_rvalid;

eth_mac_top 
eth_mac_top_inst0
( 
    .sys_clk_i  ( host_clk    ) , 
    .sys_rstn_i ( ~reset      ) , 

    .refclk     ( refclk      ) ,

    .mii_rx_clk ( mii_rx_clk  ) ,
    .mii_rxd    ( mii_rxd     ) ,   
    .mii_rx_dv  ( mii_rx_dv   ) ,

    .mrx_dma_addr   ( mrx_dma_addr   ) ,
    .mrx_dma_req    ( mrx_dma_req    ) ,
    .mrx_dma_wdata  ( mrx_dma_wdata  ) ,
    .mrx_dma_we     ( mrx_dma_we     ) ,
    .mrx_dma_gnt    ( mrx_dma_gnt    ) ,
    .mrx_dma_rdata  ( mrx_dma_rdata  ) ,
    .mrx_dma_rvalid ( mrx_dma_rvalid ) ,

    .mtx_dma_addr   ( mtx_dma_addr   ) ,
    .mtx_dma_req    ( mtx_dma_req    ) ,
    .mtx_dma_wdata  ( mtx_dma_wdata  ) ,
    .mtx_dma_we     ( mtx_dma_we     ) ,
    .mtx_dma_gnt    ( mtx_dma_gnt    ) ,
    .mtx_dma_rdata  ( mtx_dma_rdata  ) ,
    .mtx_dma_rvalid ( mtx_dma_rvalid ) 

);

MEM  
mem_inst0(
    .clk_i          ( host_clk       ) ,
    .rstn_i         ( ~reset         ) ,

    .mrx_dma_addr   ( mrx_dma_addr   ) ,
    .mrx_dma_req    ( mrx_dma_req    ) ,
    .mrx_dma_wdata  ( mrx_dma_wdata  ) ,
    .mrx_dma_we     ( mrx_dma_we     ) ,
    .mrx_dma_gnt    ( mrx_dma_gnt    ) ,
    .mrx_dma_rdata  ( mrx_dma_rdata  ) ,
    .mrx_dma_rvalid ( mrx_dma_rvalid ) ,

    .mtx_dma_addr   ( mtx_dma_addr   ) ,
    .mtx_dma_req    ( mtx_dma_req    ) ,
    .mtx_dma_wdata  ( mtx_dma_wdata  ) ,
    .mtx_dma_we     ( mtx_dma_we     ) ,
    .mtx_dma_gnt    ( mtx_dma_gnt    ) ,
    .mtx_dma_rdata  ( mtx_dma_rdata  ) ,
    .mtx_dma_rvalid ( mtx_dma_rvalid ) 
);
  //---------------------------------------------------------------------------
  //-- If the simulation is still going after 500 us then
  //-- something has gone wrong
  //---------------------------------------------------------------------------
  initial
  begin
    #550000000;
    $display("** ERROR: Simulation Running Forever");
    $finish();
  end
  //----------------------------------------------------------------------------
  // Flow Control held inactive
  //----------------------------------------------------------------------------
  assign pause_req = 1'b0;
  assign pause_val = 1'b0;



  //----------------------------------------------------------------------------
  // Simulate the MDIO
  //----------------------------------------------------------------------------
  // count through the mdio transfer
  always @(posedge mdc or posedge reset)
  begin
     if (reset) begin
        mdio_count <= 0;
        last_mdio <= 1'b0;
     end
     else begin
        last_mdio <= mdio;
        if (mdio_count >= 32) begin
           mdio_count <= 0;
        end
        else if (mdio_count != 0) begin
           mdio_count <= mdio_count + 1;
        end
        else begin // only get here if mdio state is 0 - now look for a start
           if ((mdio === 1'b1) && (last_mdio === 1'b0))
              mdio_count <= 1;
        end   
     end  
  end
  
  assign mdio = (mdio_read & (mdio_count >= 14) & (mdio_count <= 31)) ? 1'b1 : 1'bz;
  
  // only respond to phy addr 7 and reg address == 0
  always @(posedge mdc or posedge reset)
  begin
     if (reset) begin
        mdio_read <= 1'b0;  
        mdio_addr <= 1'b1; // this will go low if the address doesn't match required   
        mdio_fail <= 1'b0;
     end
     else
     begin
        if (mdio_count == 2) begin
           mdio_addr <= 1'b1;    // new access so address needs to be revalidated
           if ({last_mdio,mdio} === 2'b10)
              mdio_read <= 1'b1;
           else // take a write as a default as won't drive at the wrong time
              mdio_read <= 1'b0;
        end
        else if ((mdio_count <= 12)) begin
           // check address is phy addr/reg addr are correct
           if (mdio_count <= 7 & mdio_count >= 5) begin
              if (mdio !== 1'b1)
                 mdio_addr <= 1'b0;
           end
           else begin
              if (mdio !== 1'b0)
                 mdio_addr <= 1'b0;
           end
        end
        else if ((mdio_count == 14)) begin
           if (!mdio_read & (mdio | !last_mdio)) begin
              $display("FAIL : Write TA phase is incorrect at %t ps", $time);
           end
        end 
        else if ((mdio_count >= 15) & (mdio_count <= 30) & mdio_addr) begin
           if (!mdio_read) begin
              if (mdio_count == 20) begin
                 if (mdio) begin
                    mdio_fail <= 1;
                    $display("FAIL : Expected bit 10 of mdio write data to be 0 at %t ps", $time);
                 end
              end
              else begin
                 if (!mdio) begin
                    mdio_fail <= 1;
                    $display("FAIL : Expected all except bit 10 of mdio write data to be 1 at %t ps", $time);
                 end
              end
           end
        end 
     end     
  end

  //----------------------------------------------------------------------------
  // Clock drivers
  //----------------------------------------------------------------------------

  // drives host_clk at one third the frequency of gtx_clk
  initial
  begin
    host_clk <= 1'b0;
    #2000;
    forever
    begin
      host_clk <= 1'b0;
      #5000;
      host_clk <= 1'b1;
      #5000;
    end
  end


  initial
  begin
    refclk <= 1'b0;
    #10000;
    forever
    begin
      refclk <= 1'b0;
      #10000;
      refclk <= 1'b1;
      #10000;
    end
  end

  // drives mii_tx_clk100 at 25 MHz
  initial begin
      mii_tx_clk100 <= 0;
      forever @(posedge refclk) mii_tx_clk100 <= ~mii_tx_clk100;
  end


  // drives mii_tx_clk at 2.5 MH
  initial
  begin
    mii_tx_clk10 <= 1'b0;
    #10000;
    forever
    begin
      mii_tx_clk10 <= 1'b0;
      #200000;
      mii_tx_clk10 <= 1'b1;
      #200000;
    end
  end


  // Select between 10Mb/s and 100Mb/s MII Tx clock frequencies
  always @(mii_tx_clk10, mii_tx_clk100, current_speed)
  begin
    if (current_speed == 2'b11)
      mii_tx_clk = 1'b0;
    else if (current_speed == 2'b00)
      mii_tx_clk = mii_tx_clk10;
    else
      mii_tx_clk = mii_tx_clk100;
  end


  // Receiver and transmitter clocks are the same in this simulation
  assign mii_rx_clk = mii_tx_clk;



  //----------------------------------------------------------------------------
  // A Task to reset the MAC
  //----------------------------------------------------------------------------
  task mac_reset;
    begin
      $display("** Note: Resetting core...");

      reset <= 1'b1;
      #400000

      reset <= 1'b0;
      #1000000

      #100000
      
      $display("** Note: Timing checks are valid");
    end
  endtask // mac_reset;


  //----------------------------------------------------------------------------
  // A Task to perform a Host Configuration Write
  //----------------------------------------------------------------------------
  task host_write;
    input  [8:0] reg_address;
    input [31:0] wr_data;
  begin
    @(negedge host_clk)
    host_addr[9]          <= 1'b1;
    host_addr[8:0]        <= reg_address;
    host_miim_sel         <= 1'b0;
    host_opcode           <= 2'b01;
    host_wr_data          <= wr_data;
    @(negedge host_clk)
    host_addr[9]          <= 1'b0;
    host_addr[8:0]        <= 9'b0;
    host_miim_sel         <= 1'b1;
    host_opcode           <= 2'b11;
    host_wr_data          <= 32'b0;
  end
  endtask // procedure host_write


  //----------------------------------------------------------------------------
  // A Task to perform a Host Configuration Read
  // An extra cycle is required as the example design has an extra pipeline delay
  //----------------------------------------------------------------------------
  task host_read;
    input  [8:0] reg_address;
    output [31:0] rd_data;
  begin
    @(negedge host_clk)
    host_addr[9]          <= 1'b1;
    host_addr[8:0]        <= reg_address;
    host_miim_sel         <= 1'b0;
    host_opcode           <= 2'b11;
    @(negedge host_clk)
    host_addr[9]          <= 1'b0;
    host_addr[8:0]        <= 9'b0;
    host_miim_sel         <= 1'b1;
    host_opcode           <= 2'b11;
    @(negedge host_clk)
    @(posedge host_clk)
    rd_data                = host_rd_data;
  end
  endtask //procedure host_read

  //----------------------------------------------------------------------------
  // A Task to perform an MDIO Configuration Write
  //----------------------------------------------------------------------------
  task mdio_write_task;
    input  [4:0] phy_addr;
    input  [4:0] reg_addr;
    input [15:0] wr_data;
  begin
    @(negedge host_clk)
    host_addr[9:0]        <= {phy_addr, reg_addr};
    host_miim_sel         <= 1'b1;
    host_opcode           <= 2'b01;
    host_req              <= 1'b1;
    host_wr_data          <= wr_data;
    @(negedge host_clk)
    host_addr[9:0]        <= 10'b0;
    host_miim_sel         <= 1'b1;
    host_opcode           <= 2'b11;
    host_req              <= 1'b0;
    host_wr_data          <= 32'b0;
    @(negedge host_clk)
    while (!host_miim_rdy) begin
       @(negedge host_clk);
    end
  end
  endtask // procedure mdio_write_task


  //----------------------------------------------------------------------------
  // A Task to perform an MDIO Configuration Read
  // An extra cycle is required as the example design has an extra pipeline delay
  //----------------------------------------------------------------------------
  task mdio_read_task;
    input  [4:0] phy_addr;
    input  [4:0] reg_addr;
    output [15:0] rd_data;
  begin
    @(negedge host_clk)
    host_addr[9:0]        <= {phy_addr, reg_addr};
    host_miim_sel         <= 1'b1;
    host_opcode           <= 2'b10;
    host_req              <= 1'b1;
    @(negedge host_clk)
    host_addr[9:0]        <= 10'b0;
    host_miim_sel         <= 1'b1;
    host_opcode           <= 2'b11;
    host_req              <= 1'b0;
    @(negedge host_clk)
    while (!host_miim_rdy) begin
       @(negedge host_clk);
    end
    @(posedge host_clk)
    rd_data                = host_rd_data;
  end
  endtask //procedure mdio_read_task

  // task to perform the host configuration after reset
  task configure_mac;
  begin
    //------------------------------------------------------------------
    // Configure the MAC though the Management I/F.
    //------------------------------------------------------------------
    // add a delay to ensure the mdio logic is out of reset
    #150000

    // set up MDC frequency. Write 2E to Management configuration
    // register (Add=340). This will enable MDIO and set MDC to 2.083MHz
    // (set CLOCK_DIVIDE value to 9 dec. for 41.66MHz host_clk and
    // enable mdio)
    $display("** Note: Setting MDC Frequency to 2.3MHZ....");
    host_write(CONFIG_MANAGEMENT_ADD,{24'h0, 8'b01001001});

    // Reading Management Configuration Register (Add=340).
    $display("** Note: Reading Management Configuration  Register....");
    host_read(CONFIG_MANAGEMENT_ADD, rd_data_value);

    // confirm the write took place - i.e not still in reset
    while (rd_data_value !== 8'b01001001) begin
      $display("** Note: REtrying Host access.");
      host_write(CONFIG_MANAGEMENT_ADD,{24'h0, 8'b01001001});
      host_read(CONFIG_MANAGEMENT_ADD, rd_data_value);
    end


    // Disable Flow Control. Set top 3 bits of the flow control
    // configuration register (Add=2C0) to zero therefore disabling tx
    // and rx flow control.
    $display("** Note: Disabling tx and rx flow control...");
    host_write(CONFIG_FLOW_CTRL_ADD,32'h0);


    // Reading Flow Control Configuration Register (Add=2C0).
    $display("** Note: Reading Flow Control Configuration  Register....");
    host_read(CONFIG_FLOW_CTRL_ADD, rd_data_value);

    @(negedge host_clk)

    if (test_half_duplex == 1'b1)
    begin
      $display("Putting device into half duplex mode....");
      host_write(TRANSMITTER_ADD,{8'b00010100, 24'h0});
      host_write(RECEIVER_ADD,   {8'b00010100, 24'h0});
    end

    // Write MAC Unicast address to value DA-02-03-04-05-06 using host i/f.
    // The Unicast Address is stored in configuration registers Add=0x380
    // and Add=0x384.
    $display("** Note: Writing Unicast Address bits 31:0...");

    // Write lower bits of unicast address
    host_write(CONFIG_UNI0_CTRL_ADD,   32'h040302DA);

    $display("** Note: Writing Unicast Address bits 47:32...");
    host_write(CONFIG_UNI1_CTRL_ADD,   32'h00000605);

    // Set Address Filter to operate in Enabled Mode. Set top bit of
    // the address filter configuration register (Add=390) to
    // zero.
    $display("** Note: Setting Address Filter to Enabled Mode...");
    host_write(CONFIG_ADDR_CTRL_ADD,   32'h00000000);

    // Reading Address Filter Configuration  Register (Add=390).
    $display("** Note: Reading Address Filter Configuration  Register....");
    host_read(CONFIG_ADDR_CTRL_ADD, rd_data_value);

  end
  endtask //procedure configure_mac

  //----------------------------------------------------------------------------
  // Management process. This process sets up the configuration by
  // turning off flow control, then checks gathered statistics at the
  // end of transmission
  //----------------------------------------------------------------------------
  initial
  begin : p_management

    integer I;

    host_req       <= 1'b0;
    host_miim_sel  <= 1'b0;
    host_opcode    <= 2'b11;
    host_addr      <= 32'h0;
    host_wr_data   <= 32'h0;

    $display("** Note: Timing checks are not valid");


    //------------------------------------------------------------------
    // Change the speed to 100Mb/s and send the 4 frames
    //------------------------------------------------------------------

    $display("** Note: Timing checks are not valid");

    $display("Setting speed to 100Mb/s....");
    host_write(EMAC_CONFIG_ADD,32'b01000000000000000000000000000000);
    
    current_speed <= 2'b01;
    
    // A reset is required after any speed change
    #100000
    mac_reset;

    //------------------------------------------------------------------
    // Configure the MAC though the Management I/F.
    //------------------------------------------------------------------
    //configure_mac;
    // Signal that configuration is complete.  Other processes will now
    // be allowed to run.
    management_config_finished = 1;
    
    // Wait for 100M monitor process to complete.
    wait (tx_monitor_finished_100M == 1);
    management_config_finished = 0;

    //------------------------------------------------------------------
    // Change the speed to 10Mb/s and send the 4 frames
    //------------------------------------------------------------------

    $display("** Note: Timing checks are not valid");

    $display("Setting speed to 10Mb/s....");
    host_write(EMAC_CONFIG_ADD,32'b00000000000000000000000000000000);

    // cleanly switch the mii clock wait for mii to go low and set clock 
    // to low setting until mii_10 is low
    @(negedge mii_tx_clk); 
    current_speed <= 2'b11;
    @(negedge mii_tx_clk10);
    current_speed <= 2'b00;

    // A reset is required after any speed change
    #1000000
    mac_reset;

    //------------------------------------------------------------------
    // Configure the MAC though the Management I/F.
    //------------------------------------------------------------------
    configure_mac;
    //------------------------------------------------------------------
    // Perform MDIO reads and writes when running at 10M as this has little 
    // impact upon simulation time
    // read write from phy address 7 reg address 0
    // force bit 10 of the read value to 0
    //------------------------------------------------------------------
    mdio_read_task(7,0,rd_data_value);
    mdio_write_task(7,0,rd_data_value[15:0] & 16'hfbff);
    // Signal that configuration is complete.  Other processes will now
    // be allowed to run.
    management_config_finished = 1;
    
    // Wait for 10M monitor process to complete.
    wait (tx_monitor_finished_10M == 1);
    management_config_finished = 0;
    
    
    // Our work here is done
    $display("** failure: Simulation Stopped");
    $stop;

  end // p_management



  //----------------------------------------------------------------------------
  // Create the MII Half Duplex signals to simulate an attached PHY device
  //----------------------------------------------------------------------------
  assign mii_col = (mii_tx_en | mii_tx_er) & (mii_rx_dv | mii_rx_er);
  assign mii_crs = (mii_tx_en | mii_tx_er) | (mii_rx_dv | mii_rx_er);


  //----------------------------------------------------------------------------
  // Procedure to inject a frame into the receiver at 10/100Mb/s
  //----------------------------------------------------------------------------
  task send_frame_10_100m;
    input   `FRAME_TYP frame;
    integer column_index;
    integer I;
    reg [31:0] fcs;
    begin
      // import the frame into scratch space
      rx_stimulus_working_frame.frombits(frame);

      column_index = 0;

      // Reset the FCS calculation
      fcs = 32'b0;

      @(posedge mii_rx_clk);

      // Adding the preamble field
      for (I = 0; I < 15; I = I + 1)
      begin
        #30000;
        mii_rxd   <= 4'h5;
        mii_rx_dv <= 1'b1;
        @(posedge mii_rx_clk);
      end

      // Adding the Start of Frame Delimiter (SFD)
      #30000;
      mii_rxd   <= 4'hD;
      mii_rx_dv <= 1'b1;
      @(posedge mii_rx_clk);

      // loop over columns in frame.
      while (rx_stimulus_working_frame.valid[column_index] !== 1'b0)
      begin
        // send one column of data
        #30000;
        mii_rxd   <= {rx_stimulus_working_frame.data[column_index][3:0]};
        mii_rx_dv <= rx_stimulus_working_frame.valid[column_index];
        mii_rx_er <= rx_stimulus_working_frame.error[column_index];
        @(posedge mii_rx_clk);
        #30000;
        mii_rxd   <= {rx_stimulus_working_frame.data[column_index][7:4]};
        mii_rx_dv <= rx_stimulus_working_frame.valid[column_index];
        mii_rx_er <= rx_stimulus_working_frame.error[column_index];
        calc_crc(rx_stimulus_working_frame.data[column_index], fcs);
        column_index = column_index + 1;
        @(posedge mii_rx_clk);
    end

      // Send the CRC.
      for (I = 0; I < 4; I = I + 1)
      begin
        #30000;
        case(I)
           0 : mii_rxd    <= fcs[3:0];
           1 : mii_rxd    <= fcs[11:8];
           2 : mii_rxd    <= fcs[19:16];
           3 : mii_rxd    <= fcs[27:24];
        endcase
        mii_rx_dv  <= 1'b1;
        mii_rx_er  <= 1'b0;

        @(posedge mii_rx_clk);
        #30000;
        case(I)
           0 : mii_rxd    <= fcs[7:4];
           1 : mii_rxd    <= fcs[15:12];
           2 : mii_rxd    <= fcs[23:20];
           3 : mii_rxd    <= fcs[31:28];
        endcase
        mii_rx_dv  <= 1'b1;
        mii_rx_er  <= 1'b0;
        @(posedge mii_rx_clk);
      end

      // Clear the data lines.
      #30000;
      mii_rxd       <= 4'h0;
      mii_rx_dv     <= 1'b0;

      // Adding the minimum Interframe gap for a receiver (8 idles)
      for (I = 0; I < 15; I = I + 1)
        @(posedge mii_rx_clk);

    end
  endtask // send_frame_10_100m;


  //----------------------------------------------------------------------------
  // Stimulus process. This process will inject frames of data into the
  // PHY side of the receiver.
  //----------------------------------------------------------------------------
  initial
  begin : p_rx_stimulus

    // Initialise stimulus
    mii_rxd        = 4'h0;
    mii_rx_dv      = 1'b0;
    mii_rx_er      = 1'b0;
    tx_ifg_delay   = 8'h0;

    //-----------------------------------------------------
    // Send four frames through the MAC and Design Exampled
    // at each state Ethernet speed
    //      -- frame 0 = standard frame
    //      -- frame 1 = type frame
    //      -- frame 2 = frame containing an error
    //      -- frame 3 = standard frame with padding
    //-----------------------------------------------------


    //-----------------------------------------------------
    // 100 Mb/s speed
    //-----------------------------------------------------
    // Wait for the Management transaction to finish.
    while (management_config_finished !== 1) @(posedge management_config_finished);
    $display("Rx Stimulus: sending 4 frames at 100M ... ");

    send_frame_10_100m(frame0.tobits(0));
    send_frame_10_100m(frame1.tobits(1));
    send_frame_10_100m(frame2.tobits(2));
    send_frame_10_100m(frame3.tobits(3));

    wait (tx_monitor_finished_100M == 1);
    #100000;

    //-----------------------------------------------------
    // 100 Mb/s speed
    //-----------------------------------------------------
    // Wait for the Management transaction to finish.
    while (management_config_finished !== 1) @(posedge management_config_finished);
    $display("Rx Stimulus: sending 4 frames at 10M ... ");

    send_frame_10_100m(frame0.tobits(0));
    send_frame_10_100m(frame1.tobits(1));
    send_frame_10_100m(frame2.tobits(2));
    send_frame_10_100m(frame3.tobits(3));
    

  end // p_rx_stimulus



  //----------------------------------------------------------------------------
  // Procedure to check a transmitted frame at 10/100Mb/s
  //----------------------------------------------------------------------------
  task check_frame_10_100m;
    input `FRAME_TYP frame;
    integer column_index;
    integer I;
    reg [31:0] fcs;
  begin
    $timeformat(-9, 0, "ns", 7);

    // import the frame into scratch space
    tx_monitor_working_frame.frombits(frame);

    column_index = 0;

    // Reset the FCS calculation
    fcs = 32'b0;

    // If the current frame had an error inserted then it would have
    // been dropped by the FIFO in the design example.  Therefore
    // exit this task and move immediately on to the next frame.
    if (tx_monitor_working_frame.bad_frame !== 1'b1)
    begin

      // wait until the first real column of data to come out of RX client
      while (mii_tx_en !== 1'b1)
        @(posedge mii_tx_clk);

      // Parse over the preamble field
      while (mii_txd === 8'h05)
        @(posedge mii_tx_clk);

      // Parse over the SFD
      @(posedge mii_tx_clk);

      // Start comparing transmitted data to received data
      $display("** Note: Comparing Transmitted Frame with Injected Frame");

      // frame has started, loop over columns of frame
      while (tx_monitor_working_frame.valid[column_index] !== 1'b0)
      begin

        // The transmitted Destination Address was the Source Address
        // of the injected frame
        if (column_index < 6)
        begin
          calc_crc(tx_monitor_working_frame.data[column_index+6], fcs);
          if (mii_tx_en !== tx_monitor_working_frame.valid[column_index+6])
            $display("** ERROR: mii_tx_en incorrect during Destination Address");

          if (mii_txd !== {tx_monitor_working_frame.data[(column_index+6)][3:0]})
            $display("** ERROR: mii_txd incorrect during Destination Address");

          @(posedge mii_tx_clk);

          if (mii_tx_en !== tx_monitor_working_frame.valid[column_index+6])
            $display("** ERROR: mii_tx_en incorrect during Destination Address");

          if (mii_txd !== {tx_monitor_working_frame.data[(column_index+6)][7:4]})
            $display("** ERROR: mii_txd incorrect during Destination Address");
        end

        // The transmitted Source Address was the Destination Address
        // of the injected frame
        else if (column_index < 12)
        begin
          calc_crc(tx_monitor_working_frame.data[column_index-6], fcs);
          if (mii_tx_en !== tx_monitor_working_frame.valid[column_index-6])
            $display("** ERROR: mii_tx_en incorrect during Source Address");

          if (mii_txd !== {tx_monitor_working_frame.data[(column_index-6)][3:0]})
            $display("** ERROR: mii_txd incorrect during Source Address");

          @(posedge mii_tx_clk);

          if (mii_tx_en !== tx_monitor_working_frame.valid[column_index-6])
            $display("** ERROR: mii_tx_en incorrect during Source Address");

          if (mii_txd !== {tx_monitor_working_frame.data[(column_index-6)][7:4]})
            $display("** ERROR: mii_txd incorrect during Source Address");
        end

        // check all other data in the frame
        else
        begin
          calc_crc(tx_monitor_working_frame.data[column_index], fcs);
          if (mii_tx_en !== tx_monitor_working_frame.valid[column_index])
            $display("** ERROR: mii_tx_en incorrect");

          if (mii_txd !== {tx_monitor_working_frame.data[column_index][3:0]})
            $display("** ERROR: mii_txd incorrect");

          @(posedge mii_tx_clk);

          if (mii_tx_en !== tx_monitor_working_frame.valid[column_index])
            $display("** ERROR: mii_tx_en incorrect");

          if (mii_txd !== {tx_monitor_working_frame.data[column_index][7:4]})
            $display("** ERROR: mii_txd incorrect");
        end

        // wait for next column of data
        column_index = column_index + 1;
        @(posedge mii_tx_clk);
      end

      // Check the FCS
      // Having checked all data columns, txd must contain FCS.
      for (I = 0; I < 4; I = I + 1)
      begin
        if (mii_tx_en !== 1'b1)
          $display("** ERROR: mii_tx_en incorrect during FCS field at %t", $realtime, "ps");

        case(I)
          0 :  if (mii_txd !== fcs[3:0])
                 $display("** ERROR: mii_txd incorrect during FCS field at %t", $realtime, "ps");
          1 :  if (mii_txd !== fcs[11:8])
                 $display("** ERROR: mii_txd incorrect during FCS field at %t", $realtime, "ps");
          2 :  if (mii_txd !== fcs[19:16])
                 $display("** ERROR: mii_txd incorrect during FCS field at %t", $realtime, "ps");
          3 :  if (mii_txd !== fcs[27:24])
                 $display("** ERROR: mii_txd incorrect during FCS field at %t", $realtime, "ps");
        endcase

        @(posedge mii_tx_clk);
        if (mii_tx_en !== 1'b1)
          $display("** ERROR: mii_tx_en incorrect during FCS field at %t", $realtime, "ps");

        case(I)
          0 :  if (mii_txd !== fcs[7:4])
                 $display("** ERROR: mii_txd incorrect during FCS field at %t", $realtime, "ps");
          1 :  if (mii_txd !== fcs[15:12])
                 $display("** ERROR: mii_txd incorrect during FCS field at %t", $realtime, "ps");
          2 :  if (mii_txd !== fcs[23:20])
                 $display("** ERROR: mii_txd incorrect during FCS field at %t", $realtime, "ps");
          3 :  if (mii_txd !== fcs[31:28])
                 $display("** ERROR: mii_txd incorrect during FCS field at %t", $realtime, "ps");
        endcase

        @(posedge mii_tx_clk);
      end

    end
   end
  endtask // check_frame_10_100m


  //----------------------------------------------------------------------------
  // Monitor process. This process checks the data coming out of the
  // transmitter to make sure that it matches that inserted into the
  // receiver.
  //----------------------------------------------------------------------------

  initial
  begin : p_tx_monitor
    tx_monitor_finished_100M  <= 0;
    tx_monitor_finished_10M   <= 0;

    //-----------------------------------------------------
    // Compare the transmitted frame to the received frames
    //      -- frame 0 = minimum length frame
    //      -- frame 1 = type frame
    //      -- frame 2 = errored frame
    //      -- frame 3 = padded frame
    // Repeated for all stated speeds.
    //-----------------------------------------------------
    
    // wait for the reset to complete before starting monitor
    @(negedge reset);

    //-----------------------------------------------------
    // 100 Mb/s speed
    //-----------------------------------------------------

    // Check the frames
    check_frame_10_100m(frame0.tobits(0));
    check_frame_10_100m(frame1.tobits(0));
    check_frame_10_100m(frame2.tobits(0));
    check_frame_10_100m(frame3.tobits(0));

    #200000
    tx_monitor_finished_100M  <= 1;

    //-----------------------------------------------------
    // 10 Mb/s speed
    //-----------------------------------------------------

    // Check the frames
    check_frame_10_100m(frame0.tobits(0));
    check_frame_10_100m(frame1.tobits(0));
    check_frame_10_100m(frame2.tobits(0));
    check_frame_10_100m(frame3.tobits(0));

    #200000
    tx_monitor_finished_10M  <= 1;
    

  end // p_tx_monitor

  initial begin
    $fsdbDumpfile("wave.fsdb");
    $fsdbDumpvars();
  end

endmodule

